import createDOMElement from './createDOMElement'
import mountElement from './mountElement'
import updateNodeElement from './updateNodeElement'
import updateTextNode from './updateTextNode'
import unmountNode from './unmountNode'
import diffComponent from './diffComponent'

export default function diff(virtualDOM, container, oldDOM) {
  const oldVirtualDOM = oldDOM && oldDOM._virtualDOM
  const oldComponent = oldVirtualDOM && oldVirtualDOM.component
  if (!oldDOM) {
    mountElement(virtualDOM, container)
  }

  // 是组件的情况
  else if (typeof virtualDOM.type === 'function') {
    diffComponent(virtualDOM, oldComponent, oldDOM, container)
  }

  // 节点类型不同
  else if (
    virtualDOM.type !== oldVirtualDOM.type &&
    typeof virtualDOM !== 'function'
  ) {
    const newElement = createDOMElement(virtualDOM)
    oldDOM.parentNode.replaceChild(newElement, oldDOM)
  }

  // 节点类型相同
  else if (oldVirtualDOM && virtualDOM.type === oldVirtualDOM.type) {
    if (virtualDOM.type === 'text') {
      // update content
      updateTextNode(virtualDOM, oldVirtualDOM, oldDOM)
    } else {
      // update attribute
      updateNodeElement(oldDOM, virtualDOM, oldVirtualDOM)
    }

    // 将拥有 key 属性的子元素放入单独的对象
    const keyedElements = {}
    for (let i = 0, len = oldDOM.childNodes.length; i < len; i++) {
      const domElement = oldDOM.childNodes[i]

      if (domElement.nodeType === 1) {
        const key = domElement.getAttribute('key')
        if (key) {
          keyedElements[key] = domElement
        }
      }
    }

    const hasNoKey = Object.keys(keyedElements).length === 0

    if (hasNoKey) {
      // 比对子节点
      virtualDOM.children.forEach((child, i) => {
        diff(child, container, oldDOM.childNodes[i])
      })
    }
    // 循环 virtualDOM 的子元素获取其 key 属性
    else {
      virtualDOM.children.forEach((child, i) => {
        const key = child.props.key
        if (key) {
          const domElement = keyedElements[key]
          if (domElement) {
            // 当前位置元素是否为期望元素
            if (oldDOM.childNodes[i] && oldDOM.childNodes[i] !== domElement) {
              oldDOM.insertBefore(domElement, oldDOM.childNodes[i])
            } else {
              // 新增元素
              mountElement(child, oldDOM, oldDOM.childNodes[i])
            }
          }
        }
      })
    }

    // 删除节点
    const oldChildNodes = oldDOM.childNodes // 获取旧节点
    if (oldChildNodes.length > virtualDOM.children.length) {
      if (hasNoKey) {
        for (
          let i = oldChildNodes.length - 1;
          i > virtualDOM.children.length - 1;
          i--
        ) {
          unmountNode(oldChildNodes[i])
        }
      } else {
        // 通过 key 删除节点
        for (let i = 0; i < oldChildNodes.length; i++) {
          const oldChild = oldChildNodes[i]
          const oldChildKey = oldChild._virtualDOM.props.key
          let found = false
          for (let n = 0; n < virtualDOM.children.length; n++) {
            found = true
            break
          }
        }
        if (!found) {
          unmountNode(oldChild)
        }
      }
    }
  }
}
